package com.spzx.cart.service.impl;

import com.spzx.product.api.domain.CartItem;
import com.spzx.cart.service.CartService;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.vo.ProductSkuVO;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Resource
    RedisTemplate redisTemplate;
    @Resource
    RemoteProductService remoteProductService;
    @Override
    public boolean add2Cart(Long skuId, Integer skuNum) {
        Long userId = SecurityUtils.getUserId();
        BoundHashOperations cart = getCart();
        //获取购物车中 本次新增的sku对应的购物项
        Object obj = cart.get(skuId.toString());
        //添加商品到购物车： 将要添加的商品转为购物车中的数据并存入
        CartItem cartItem ;
        if(obj==null){
            //加购的商品种类不能超过30： 不同sku的数量不能超过30
            if(cart.size()+1 >5){
                throw new ServiceException("添加商品种类不能超过5");
            }
            //1、如果购物车中没有该商品，初始化添加购物项到购物车中
            //使用redis的hash结构来存储： cart:userId   skuId  cartItem
            cartItem = new CartItem();
            cartItem.setSkuId(skuId);
            cartItem.setSkuNum(skuNum);
            cartItem.setCreateTime(new Date());
            cartItem.setUpdateTime(new Date());
            cartItem.setUserId(userId);
            R<ProductSkuVO> skuVOR = remoteProductService.getSkuDetails(skuId);
            if(R.SUCCESS != skuVOR.getCode()){
                throw new ServiceException("商品数据不存在");
            }
            ProductSkuVO skuVO = skuVOR.getData();
            cartItem.setSkuName(skuVO.getProductSku().getSkuName());//需要根据skuId查询sku详情数据
            cartItem.setThumbImg(skuVO.getProductSku().getThumbImg());
            cartItem.setCartPrice(skuVO.getProductSku().getSalePrice());
            cartItem.setSkuPrice(skuVO.getProductSku().getSalePrice());

        }else{
            //2、如果购物车中已存在该商品，修改该购物项的数量
            cartItem = (CartItem) obj;
            cartItem.setSkuNum(cartItem.getSkuNum()+skuNum);
            cartItem.setUpdateTime(new Date());
        }
        //使用redis保存购物项数据
        // 购物车数据缓存在redis中，java代码加载修改后 必须重新设置回redis
        cart.put(skuId.toString(),cartItem);

        return true;
    }

    private BoundHashOperations getCart() {
        //0、获取用户的购物车
        BoundHashOperations cart = redisTemplate.boundHashOps("spzx:cart:" + SecurityUtils.getUserId());
        return cart;
    }

    @Override
    public List<CartItem> cartList() {
        BoundHashOperations cart = getCart();
        //同步购物车中所有商品的价格
        List<CartItem> cartItems = cart.values();
        cartItems.forEach(cartItem -> {
            R<ProductSkuVO> skuVOR = remoteProductService.getSkuDetails(cartItem.getSkuId());
            if(R.SUCCESS != skuVOR.getCode()){
                throw new ServiceException("商品数据不存在");
            }
            cartItem.setSkuPrice(skuVOR.getData().getSkuPrice().getSalePrice());
            //将修改后的cartItem同步到redis中
            cart.put(cartItem.getSkuId().toString() , cartItem);
        });
        return cartItems;
    }

    @Override
    public boolean deleteCart(Long skuId) {
        BoundHashOperations cart = getCart();
//        cart.delete(skuId.toString());
        return cart.delete(skuId.toString())>0;
    }
    /*
        使用Hash保存购物车数据的原因：
            1、使用List保存购物车数据：
                cart:userId  List
                            {skuId:1 , skuNum:1 , 。。。。}
                            {skuId:2 , skuNum:100 , 。。。。}
            2、购物车的操作包括：
                添加商品到购物
                修改购物项数量:
                    List实现：
                        1、先获取所有的购物项
                        2、遍历所有的购物项 比较 判断是不是需要修改的那个购物项
                修改购物项的选中状态
                删除指定购物项.....

                以上的大量操作都需要通过键定位 集合中的一条记录，进行操作
                List/Set都不容易直接根据skuId获取到购物项
                Hash: key -val
                    可以快速根据键获取到值
     */
    @Override
    public boolean checkCart(Long skuId, Integer status) {
        BoundHashOperations cart = getCart();
        Object obj = cart.get(skuId.toString());
        if(obj==null){
            throw new ServiceException("数据不存在");
        }
        CartItem cartItem = (CartItem) obj;
        cartItem.setIsChecked(status);
        cart.put(skuId.toString() , cartItem);
        return true;
    }

    @Override
    public boolean allCheckCart(Integer status) {
        BoundHashOperations cart = getCart();
        //获取购物车中所有的购物项和skuId映射的 对象集合 再遍历
        cart.entries().forEach((skuIdStr , cartItem)->{
            CartItem ci = (CartItem) cartItem;
            ci.setIsChecked(status);
            cart.put(skuIdStr , ci);
        });
        return true;
    }

    @Override
    public boolean clearCart() {
//        BoundHashOperations cart = getCart();
        //清空购物车：只需要将用户再redis中的购物车删除即可(hash)
        redisTemplate.delete("spzx:cart:" + SecurityUtils.getUserId());
        return true;
    }

    @Override
    public List<CartItem> getCheckedCartItems() {
        BoundHashOperations cart = getCart();
        List<CartItem> cartItems = cart.values();

        return cartItems.stream()
                .filter(cartItem -> cartItem.getIsChecked().longValue() == 1l)
                .collect(Collectors.toList());
    }

    @Override
    public Boolean delCheckedCartItems() {
        BoundHashOperations<String,String,CartItem> cart = getCart();
        cart.entries().forEach((skuIdStr , cartItem)->{
            if(cartItem.getIsChecked().intValue() == 1){
                cart.delete(skuIdStr);
            }
        });
        return true;
    }

    @Override
    public Boolean delCheckedCartItems(Long userId) {
        BoundHashOperations<String,String,CartItem> cart = redisTemplate.boundHashOps("spzx:cart:" + userId);
        cart.entries().forEach((skuIdStr , cartItem)->{
            if(cartItem.getIsChecked().intValue() == 1){
                cart.delete(skuIdStr);
            }
        });
        return true;
    }

}
